#--*-- coding:utf-8 --*--

import sys
import os
import os.path
import platform
import shutil
import math
from pyqt4_pyside import *
from aber import *
    
from logwidget import LogWidget
from errorinfowidget import ErrorInfoWidget

NoneString =  "<font color=red>NONE</font>"

def calcElensParams(elenspos,  wd,  A,  B):
    u"""计算像平面位置，以及静电透镜的参数
    elenspos：静电透镜位置
    wd：工作距离
    A：常量1，静电透镜的伸出量
    B：常量2，j静电透镜参数
    """
    if elenspos < - A: #静电透镜缩到物镜内
        imageplane = wd - B - A
        elensdistance = wd - elenspos - A
    else:             #静电透镜在物镜外，是工作距离的基准
        imageplane = wd - B + elenspos
        elensdistance = wd
    
    return imageplane,  elensdistance


class CalcPage2(QtGui.QWidget):
    def __init__(self,  parent=None):
        super(CalcPage2,  self).__init__(parent)
        
        self.readSettings()
        
        hbox1 = QtGui.QHBoxLayout()
        self.filePathEdit = QtGui.QLineEdit()
        self.filePathEdit.setReadOnly(True)
        self.openPathButton = QtGui.QPushButton(u"选择文件...")
        hbox1.addWidget(self.filePathEdit)
        hbox1.addWidget(self.openPathButton)
        
        hbox2 = QtGui.QHBoxLayout()
        self.settingsGlobalButton = QtGui.QPushButton(u"设置全局...")
        self.settingsWDButton = QtGui.QPushButton(u"设置工作距离...")
        self.settingsElensPosButton = QtGui.QPushButton(u"设置透镜位置...")
        self.settingsApertureSizeButton = QtGui.QPushButton(u"设置光阑大小...")
        self.settingsLandEnergyButton = QtGui.QPushButton(u"设置落点能量...")
        self.testButton = QtGui.QPushButton(u"测试")
        self.testButton.setDisabled(True)
        self.startButton = QtGui.QPushButton(u"开始计算")
        self.startButton.setDisabled(True)
        hbox2.addWidget(self.settingsGlobalButton)
        hbox2.addWidget(self.settingsWDButton)
        hbox2.addWidget(self.settingsElensPosButton)
        hbox2.addWidget(self.settingsApertureSizeButton)
        hbox2.addWidget(self.settingsLandEnergyButton)
        hbox2.addWidget(self.testButton)
        hbox2.addWidget(self.startButton)
        
        self.progressBar = QtGui.QProgressBar()
        self.progressBar.setRange(0, 100)
        self.progressBar.setValue(0)
        self.logWidget = LogWidget()
        
        self.resultButton = QtGui.QPushButton(u"结果提取")
        self.resultButton.setDisabled(True)
        hbox3 = QtGui.QHBoxLayout()
        hbox3.addStretch()
        hbox3.addWidget(self.resultButton)
        
        vbox = QtGui.QVBoxLayout(self)
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        vbox.addWidget(self.progressBar)
        vbox.addWidget(self.logWidget)
        vbox.addLayout(hbox3)
        
        self.openPathButton.clicked.connect(self.onOpenPathButtonClicked)
        self.settingsGlobalButton.clicked.connect(self.onSettingsGlobal)
        self.settingsWDButton.clicked.connect(self.onSettingsWD)
        self.settingsElensPosButton.clicked.connect(self.onSettingsElensPos)
        self.settingsApertureSizeButton.clicked.connect(self.onSettingsApertureSize)
        self.settingsLandEnergyButton.clicked.connect(self.onSettingsLandEnergy)
        self.testButton.clicked.connect(self.onStartButtonClicked)
        self.startButton.clicked.connect(self.onStartButtonClicked)
        self.resultButton.clicked.connect(self.onResultButtonClicked)
        #self.setStyleSheet("background-color: rgb(200, 85, 0);")
        
    def onResultButtonClicked(self):
        with file(self.resultInputFileName) as f:
            self.logWidget.addLogString("<br/><br/>")
            for i in range(6):
                line = f.readline()
                if line:
                    self.logWidget.addLogString(line.decode(sys.getfilesystemencoding()))
                else:
                    break
        try:
            act = self.resultThread.isActive()
        except:
            pass
        else:
            if act:
                self.logWidget.addLogString(u"<br/><br/>结果提取进行中...")
                return
        self.resultThread = ResultThread(self.resultInputFileName)
        self.resultThread.datcount.connect(self.progressBar.setValue)
        self.resultThread.logdata.connect(self.logWidget.addLogString)
        self.resultThread.start()

    def onOpenPathButtonClicked(self):
        path = QtGui.QFileDialog.getOpenFileName(self,  u"选择aber的数据文件",  "",  "aber data(*.dat)")
        if isinstance(path,  tuple): #pyside return a tuple
            path = path[0]
        if path:
            self.filePathEdit.setText(path)
            self.testButton.setEnabled(True)
            self.startButton.setEnabled(True)
            self.resultInputFileName = os.path.join(path[:-4], "datalog.txt")
            if os.path.exists(self.resultInputFileName):
                self.resultButton.setEnabled(True)
            
            self.updateCalcInfo()
            
            self.logWidget.addLogString(u"<br/>")
            self.logWidget.addLogString(u"选择文件：{}".format(path))
            self.aberDatInfo(path)
            self.logWidget.addLogString(u"工作距离大小：{}".format(' '.join(self.wdList) if self.wdList else NoneString))
            self.logWidget.addLogString(u"静电透镜位置列表：{}".format(' '.join(self.elensPosList) if self.elensPosList else NoneString))
            self.logWidget.addLogString(u"光阑大小：{}".format(' '.join(self.apertureSizeList) if self.apertureSizeList else NoneString))
            self.logWidget.addLogString(u"落点能量：{}".format(' '.join(self.landEnergyList) if self.landEnergyList else NoneString))
            self.logWidget.addLogString(u"需进行 {} 次ABER计算<br/>".format(self.calc_count))

    def aberDatInfo(self,  path):
        d = AberDatFile(path)
        dir = os.path.dirname(path)
        fs = d.getDependFileNames()
        self.logWidget.addLogString(u"依赖文件：{}".format(fs))
        for s in fs:
            if (os.path.exists(os.path.join(dir, s))):
                self.logWidget.addLogString(u"{}：找到".format(s))
            else:
                self.logWidget.addErrorString(u"{}：未找到".format(s))
            try:
                if (s.startswith(self.elensGlobal[2])):
                    self.logWidget.addLogString(u"静电透镜前缀<b>{}</b>匹配文件<b>{}</b>".format(self.elensGlobal[2],  s))
                else:
                    print "not agree with {}".format(s)
            except:
                pass
            
        
    def updateCalcInfo(self):
        len1 = len(self.wdList) if self.wdList else 1
        len2 = len(self.elensPosList) if self.elensPosList else 1
        len3 = len(self.apertureSizeList) if self.apertureSizeList else 1
        len4 = len(self.landEnergyList) if self.landEnergyList else 1
        
        self.calc_count = len1 * len2 * len3 * len4
        self.progressBar.setRange(0,  self.calc_count)
        self.progressBar.setValue(0)
        
    def onSettingsGlobal(self):
        dlg = CalcElensGlobalDialog()
        if self.elensGlobal and len(self.elensGlobal)==3:
            dlg.spinbox_A.setValue(float(self.elensGlobal[0]))
            dlg.spinbox_B.setValue(float(self.elensGlobal[1]))
            dlg.elensPrefixEdit.setText(str(self.elensGlobal[2]))
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.elensGlobal = [dlg.spinbox_A.value(),  dlg.spinbox_B.value(),  dlg.elensPrefixEdit.text()]
            self.logWidget.addLogString(u"全局参数生效")
        
    def onSettingsWD(self):
        dlg = ListSettingsDialog(u"设置工作距离",  self.wdList)
        dlg.setSpinBoxDecimalsAndStep(1,  0.5)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.wdList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"工作距离大小：{}".format(' '.join(self.wdList) if self.wdList else NoneString))
        
    def onSettingsElensPos(self):
        dlg = ListSettingsDialog(u"设置静电透镜位置",  self.elensPosList)
        dlg.setSpinBoxDecimalsAndStep(1,  0.5)
        dlg.startValueEdit.setRange(-100,  100)
        dlg.endValueEdit.setRange(-100, 100)
        dlg.stepValueEdit.setRange(-100, 100)
        dlg.singleValueEdit.setRange(-100, 100)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.elensPosList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"静电透镜位置列表：{}".format(' '.join(self.elensPosList) if self.elensPosList else NoneString))
        
    def onSettingsApertureSize(self):
        dlg = ListSettingsDialog(u"设置光阑大小",  self.apertureSizeList)
        dlg.setSpinBoxDecimalsAndStep(3,  0.005)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.apertureSizeList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"光阑大小：{}".format(' '.join(self.apertureSizeList) if self.apertureSizeList else NoneString))
        
    def onSettingsLandEnergy(self):
        dlg = ListSettingsDialog(u"设置落点能量",  self.landEnergyList)
        dlg.setSpinBoxDecimalsAndStep(0,  100)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.landEnergyList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"落点能量：{}".format(' '.join(self.landEnergyList) if self.landEnergyList else NoneString))
               
    def onStartButtonClicked(self):
        rootaberfilePath = self.filePathEdit.text()
        if (not (self.landEnergyList and self.apertureSizeList and self.wdList and self.elensPosList)): #note this!!!!
            self.logWidget.addLogString(u"<br/><br/>某循环参数列表为空，停止计算")
            return
            
        if (not (self.elensGlobal and len(self.elensGlobal)==3)):
            self.logWidget.addLogString(u"<br/><br/>静电透镜全局参数未设置，停止计算")
            return
            
        try:
            act = self.calcThread.isActive()
        except:
            pass
        else:
            if act:
                self.logWidget.addLogString(u"<br/><br/>计算进行中...")
                return
        self.calcThread = CalcThread(rootaberfilePath, self.elensGlobal, self.wdList, self.elensPosList , self.apertureSizeList, self.landEnergyList)
        if self.sender() == self.testButton:
            self.calcThread.testFlag = True
        self.calcThread.calccount.connect(self.progressBar.setValue)
        self.calcThread.logdata.connect(self.logWidget.addLogString)
        self.calcThread.start()
        
    def readSettings(self):
        settings = QtCore.QSettings()
        settings.beginGroup("calc2")
        self.wdList = self.makesurelist(settings.value("wdlist", None))
        self.elensPosList = self.makesurelist(settings.value("elensposlist",  None))
        self.apertureSizeList = self.makesurelist(settings.value("aperturesizelist",  None))
        self.landEnergyList = self.makesurelist(settings.value("landenergylist",  None))
        self.elensGlobal = settings.value("elensglobal",  None)
        settings.endGroup()

    def makesurelist(self, data):
        if not isinstance(data, list):
            data = [data]
        return data
        
    def writeSettings(self):
        settings=QtCore.QSettings()
        settings.beginGroup("calc2")
        settings.setValue("wdlist", self.wdList)
        settings.setValue("elensposlist", self.elensPosList)
        settings.setValue("aperturesizelist",  self.apertureSizeList)
        settings.setValue("landenergylist",  self.landEnergyList)
        settings.setValue("elensglobal",  self.elensGlobal)
        settings.endGroup()
        
class ResultThread(QtCore.QThread):
    logdata = QtCore.Signal(unicode)
    datcount = QtCore.Signal(int)
    def __init__(self,  inputfilename,  parent = None):
        super(ResultThread, self).__init__(parent)
        self.inputfilename = inputfilename
        
    def run(self):
        inputfile = file(self.inputfilename)
        linecount = -1
        outputfile = file(os.path.join(os.path.dirname(self.inputfilename), "result.cache"),  "w")
        for i in range(7):
            line = inputfile.readline()
            if line:
                #write to file
                outputfile.write(line)
                if line.startswith("wdlist"):
                    self.wdlist = line.split()[1:]
                elif line.startswith("elensposlist"):
                    self.elensposlist = line.split()[1:]
                elif line.startswith("aperturesizelist"):
                    self.aperturesizelist = line.split()[1:]
                elif line.startswith("landenergylist"):
                    self.landenergylist = line.split()[1:]
                linecount += 1
            else:
                break
        if linecount !=  6:
            self.logdata.emit(u"数据文件错误，停止提取")
            return
        else:
            self.logdata.emit('wdlist ' + ' '.join(self.wdlist))
            self.logdata.emit('elensposlist ' + ' '.join(self.elensposlist))
            self.logdata.emit('aperturesizelist '+ ' '.join(self.aperturesizelist))
            self.logdata.emit('landenergylist ' + ' '.join(self.landenergylist))
            self.allcount = len(self.wdlist) * len(self.elensposlist) * len(self.aperturesizelist) * len(self.landenergylist)
            self.logdata.emit("all files: {}".format(self.allcount))
        
        #write to file
        outputfile.write("wd, elenspos, aperturessize, landenergy, ai, beamspot, sphericalaber, chromaticaber, excitation, sensitivities\n")

           
        for row in range(self.allcount):
            line = inputfile.readline()
            if not line:
                self.logdata.emit(u"数据文件错误，停止提取")
                break
            items=line.decode(sys.getfilesystemencoding()).split(',')
            if len(items)!=5:
                self.logdata.emit(u"数据文件错误，停止提取")
                return
                
            resfile = AberResFile(items[4].strip())
            newitems = items[:4]
            if resfile.isValid():
                ai = resfile.getAi()
                beamspot=resfile.getBeamSpotDiameter()
                sphericalaber=resfile.getSphericalAber()
                chromaticaber=resfile.getChromaticAB()
                mexcitation=resfile.getMLensExcitation()
                sensitivities=resfile.getDeflectionSensitivities()
                newitems.extend([str(ai),  str(beamspot),  str(sphericalaber),  str(chromaticaber),  str(mexcitation),  str(sensitivities)])
            else:
                newitems.extend(['None']*5)
            #write to file
            outputfile.write(", ".join(newitems)+"\n")
            linecount += 1
            self.datcount.emit(row+1)
        
class CalcThread(QtCore.QThread):
    logdata = QtCore.Signal(unicode)
    calccount = QtCore.Signal(int)
    def __init__(self,  rootFile,  elensglobal,  wd,  elenspos,  aperture, landenergy,  parent=None):
        super(CalcThread,  self).__init__(parent)
        self.rootAberFile = rootFile
        self.elensGlobal = [float(elensglobal[0]),  float(elensglobal[1]),  elensglobal[2]]
        self.wdList = wd
        self.elensPosList = elenspos
        self.apertureSizeList = aperture
        self.landEnergyList = landenergy
        self.updateCalcInfo()
        self.testFlag = False #if we donot want to call aber.exe, set this to True
        
    def updateCalcInfo(self):
        len1 = len(self.wdList) if self.wdList else 1
        len2 = len(self.elensPosList) if self.elensPosList else 1
        len3 = len(self.apertureSizeList) if self.apertureSizeList else 1
        len4 = len(self.landEnergyList) if self.landEnergyList else 1
        self.calc_count = len1 * len2 * len3 * len4
        
        self.aberfilename = os.path.basename(self.rootAberFile)
        self.aberresfilename = self.aberfilename[:-4]+".res"
        aberdir = os.path.dirname(self.rootAberFile)
        self.calcrootdir = self.rootAberFile[:-4]  #remove .dat
        print self.calcrootdir
        if not os.path.exists(self.calcrootdir):
            os.mkdir(self.calcrootdir)
            
        self.aberDatFile = AberDatFile(self.rootAberFile)
        self.dependedFiles = self.aberDatFile.getDependFileNames()
        for f in self.dependedFiles:
            if f.endswith('.axv'):
                self.axvfilename = f
        os.chdir(self.calcrootdir)
        
        self.datalogfile = file("datalog.txt",  'w')
        self.datalogfile.write("aberfile: {}\n\n".format(self.rootAberFile.encode(sys.getfilesystemencoding())))
        self.datalogfile.write("wdlist: {}\nelensposlist: {}\naperturesizelist: {}\nlandenergylist: {}\n\n"
                               .format(' '.join(self.wdList),  
                               ' '.join(self.elensPosList),  
                               ' '.join(self.apertureSizeList),  
                               ' '.join(self.landEnergyList)))
        self.datalogfile.flush()
        self.location = [self.wdList[0],  self.elensPosList[0],  self.apertureSizeList[0], self.landEnergyList[0]]
        
    def run(self):
        self.logdata.emit(os.environ['PATH'].decode(sys.getfilesystemencoding( )))
        self.calc_count = 0
        
        for wd in self.wdList:
            self.location[0] = wd
            self.calcEachWD(wd)

    def calcEachWD(self,  wd):
        wd_dir = u"工作距离{}".format(wd)
        self.logdata.emit(u"<br/><br/>当前工作距离：{}".format(wd))
##        if not os.path.exists(wd_dir):
##            os.mkdir(wd_dir)
##        os.chdir(wd_dir)  #change into
        
        # Note: no parameters depends on "wd" only!!
        
        for  elenspos in self.elensPosList:
            self.location[1] = elenspos
            self.calcEachElensPos(elenspos,  wd)
            
##        os.chdir("..")
        
    def calcEachElensPos(self,  elenspos,  currentWD):
        ep_dir = u"透镜位置{}".format(elenspos)
        self.logdata.emit(u"{}当前透镜位置：{}".format('&nbsp;'*4,  elenspos))
##        if not os.path.exists(ep_dir):
##            os.mkdir(ep_dir)
##        os.chdir(ep_dir)  #change into
        
        imageplane,  elensdistance = calcElensParams(float(elenspos),  float(currentWD),  self.elensGlobal[0],  self.elensGlobal[1])
        
        self.axvfilename = "{}-{:03d}.axv".format(self.elensGlobal[2],  int(elensdistance*10))
        self.aberDatFile.setImagePlane(imageplane)
        self.aberDatFile.setElensPos(elenspos)
        self.aberDatFile.setElensName(self.axvfilename)
        #update dependsfiles
        self.dependedFiles = self.aberDatFile.getDependFileNames()
        
        for aperture in self.apertureSizeList:
            self.location[2]=aperture
            self.calcEachAperture(aperture)
        
##        os.chdir("..") # elenspos
        
    def calcEachAperture(self,  aperture):
        ap_dir = u"光阑大小{}".format(aperture)
        self.logdata.emit(u"{}当前光阑大小：{}".format('&nbsp;'*8,  aperture))
##        if not os.path.exists(ap_dir):
##            os.mkdir(ap_dir)
##        os.chdir(ap_dir) #change into
        
        self.aberDatFile.setRealApertureDiameter(aperture)
        
        for landenergy in self.landEnergyList:
            self.location[3]=landenergy
            self.calcEachLandenergy(landenergy)
##        os.chdir("..")  # aperture
        
    def calcEachLandenergy(self,  landenergy):
        le_dir = u"落点能量{}".format(landenergy)
        self.logdata.emit(u"{}当前落点能量：{}".format('&nbsp;'*12,  landenergy))
##        if not os.path.exists(le_dir):
##            os.mkdir(le_dir)
##        os.chdir(le_dir) # changed into
        print "value", landenergy
        le = float(landenergy)
        self.aberfilename = u"aber_{}_{}_{}_{}.dat".format(self.location[0], self.location[1], self.location[2], self.location[3])
        self.aberresfilename = self.aberfilename[:-4]+'.res'
        if (os.path.exists(self.aberresfilename)):
            self.logdata.emit(u"{}<font color=green>{}已存在，跳过本次计算</font>".format('&nbsp;'*12,  self.aberresfilename))
        
        volts = (le+8000,  le,  le)
        self.aberDatFile.setELensVoltsAndName(volts, self.axvfilename)

        self.aberDatFile.save(self.aberfilename)
        
        for f in self.dependedFiles:
            if os.path.exists(f):
                continue
            try:
                shutil.copyfile(os.path.abspath("../%s" % f), f)
            except:
                try:
                    shutil.copyfile(os.path.abspath("../../../../%s" % f), f)
                except:
                    try:
                        shutil.copyfile(os.path.abspath("../../../%s" % f),  f)
                    except:
                        self.logdata.emit(u"{}<font color=red>文件未找到：{}</font>".format('&nbsp;'*12,  f))
                
        if not self.testFlag:
            ret = callMunroAber(self.aberfilename)
            self.logdata.emit(u"{}<b>aber结果：</b>{}".format('&nbsp;'*12,  ret))
            self.datalogfile.write("{:8s},{:8s},{:8s},{:8s},{}\n"
                                   .format(self.location[0], self.location[1], self.location[2], self.location[3], 
                                           os.path.abspath(self.aberfilename).encode(sys.getfilesystemencoding())))
            self.datalogfile.flush()
##        os.chdir("..")  #landenergy out
        self.calc_count += 1
        self.calccount.emit(self.calc_count)
        
    def writeResult(self, data):
        self.writeOneResult(data,  0,  u"激励.txt")
        self.writeOneResult(data, 1,  u"束班.txt")
        self.writeOneResult(data, 2,  u"偏转灵敏度.txt")
        
    def writeOneResult(self, data,  index,  filename):
        file_data = []
        # 落点能量为第一行， 每行 对应不同光阑大小
        line_items = ["%15s" % "aperture"]
        for le in self.landEnergyList:
            line_items.append("%15s" % le)
        line_items.append('\n')
        file_data.append(' '.join(line_items)) # header line
        for row in range(len(self.apertureSizeList)):
            line_items = ["%15s" % self.apertureSizeList[row]]
            for col in range(len(self.landEnergyList)):
                line_items.append("%15s" % data[row][col][index])
            line_items.append('\n')
            file_data.append(' '.join(line_items))
            
        with open(filename, 'w') as f:
            f.writelines(file_data)
            self.logdata.emit(u"提取文件：{}".format(filename))
        
class CalcElensGlobalDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        super(CalcElensGlobalDialog, self).__init__(parent)
        self.setWindowTitle(u"静电透镜的全局参数设置")
        
        self.spinbox_A = QtGui.QDoubleSpinBox()
        self.spinbox_A.setValue(4)
        self.spinbox_B = QtGui.QDoubleSpinBox()
        self.spinbox_B.setValue(6)
        self.elensPrefixEdit = QtGui.QLineEdit("oe-982") 
        
        self.okButton = QtGui.QPushButton(u"确定")
        
        formlayout = QtGui.QFormLayout()
        formlayout.addRow(u"透镜伸出量(A)",  self.spinbox_A)
        formlayout.addRow(u"透镜常量(B)",  self.spinbox_B)
        formlayout.addRow(u"透镜文件前缀",  self.elensPrefixEdit)
        
        hbbox = QtGui.QHBoxLayout()
        hbbox.addStretch(1)
        hbbox.addWidget(self.okButton)
        
        vbox = QtGui.QVBoxLayout(self)
        vbox.addLayout(formlayout)
        vbox.addStretch(0)
        vbox.addLayout(hbbox)
        
        self.okButton.clicked.connect(self.accept)
        
class ListSettingsDialog(QtGui.QDialog):
    def __init__(self, title="",  dataList=None,  parent=None):
        super(ListSettingsDialog, self).__init__(parent)
        self.setWindowTitle(title)
        
        self.infoWidget = ErrorInfoWidget()
        self.infoWidget.hide()
        
        groupBox1 = QtGui.QGroupBox(u"添加范围(开始、结束、步长)")
        hbox1 = QtGui.QHBoxLayout(groupBox1)
        self.startValueEdit = self.createSpinBox(0,  300001)
        self.endValueEdit = self.createSpinBox(0,  300001)
        self.stepValueEdit = self.createSpinBox(-10000,  10000)
        self.addRangeValueButton = QtGui.QPushButton(u"添加")
        hbox1.addWidget(self.startValueEdit)
        hbox1.addWidget(self.endValueEdit)
        hbox1.addWidget(self.stepValueEdit)
        hbox1.addWidget(self.addRangeValueButton)
        
        groupBox2 = QtGui.QGroupBox(u"添加单个值")
        hbox2 = QtGui.QHBoxLayout(groupBox2)
        self.singleValueEdit = self.createSpinBox(0,  10000)
        self.addSingleValueButton = QtGui.QPushButton(u"添加")
        hbox2.addWidget(self.singleValueEdit)
        hbox2.addWidget(self.addSingleValueButton)
        
        hbbox = QtGui.QHBoxLayout()
        self.okButton = QtGui.QPushButton(u"确定")
        self.removeButton = QtGui.QPushButton(u"移除")
        self.clearButton = QtGui.QPushButton(u"清空")
        hbbox.addWidget(self.clearButton)
        hbbox.addWidget(self.removeButton)
        hbbox.addStretch(0)
        hbbox.addWidget(self.okButton)
        
        self.listView = QtGui.QListView()
        vbox = QtGui.QVBoxLayout(self)
        #vbox.addWidget(self.infoWidget)
        vbox.setMenuBar(self.infoWidget)
        vbox.addWidget(groupBox1)
        vbox.addWidget(groupBox2)
        vbox.addWidget(self.listView)
        vbox.addLayout(hbbox)
        
        self._dataList = dataList if dataList else []
        self.listModel = QtGui.QStringListModel(self._dataList);
        self.listView.setModel(self.listModel)
        
        self.addRangeValueButton.clicked.connect(self.onAddRangeButtonClicked)
        self.addSingleValueButton.clicked.connect(self.onAddSingleButtonClicked)
        self.clearButton.clicked.connect(self.onClearButtonClicked)
        self.removeButton.clicked.connect(self.onRemoveButtonClicked)
        self.okButton.clicked.connect(self.onOkButtonClicked)
        
    def setInfo(self, text):
        self.infoWidget.setInfoText(text)
        if self.infoWidget.isHidden():
            self.infoWidget.show()
    
    def setSpinBoxDecimalsAndStep(self,  decimal,  step):
        self.startValueEdit.setDecimals(decimal)
        self.startValueEdit.setSingleStep(step)
        self.stepValueEdit.setDecimals(decimal)
        self.stepValueEdit.setSingleStep(step)
        self.endValueEdit.setDecimals(decimal)
        self.endValueEdit.setSingleStep(step)
        self.singleValueEdit.setDecimals(decimal)
        self.singleValueEdit.setSingleStep(step)
    
    def onAddRangeButtonClicked(self):
        start = self.startValueEdit.value()
        end = self.endValueEdit.value()
        step = self.stepValueEdit.value()
        if (math.fabs(step) < 1e-4): # step is zero
            self.setInfo(u"步长为零")
            return
        n  = (end-start)/step
        if n<0 or n>100: #too many values
            self.setInfo(u"数据不合理")
            return
        
        flag = (start<=end)
            
        while (flag == (start <= end)):
            row = self.listModel.rowCount()
            self.listModel.insertRows(row,  1)
            self.listModel.setData(self.listModel.index(row),  str(start))
            start += step
        
        
    def onAddSingleButtonClicked(self):
        row = self.listModel.rowCount()
        self.listModel.insertRows(row,  1)
        self.listModel.setData(self.listModel.index(row),  str(self.singleValueEdit.value()))
        
    def onClearButtonClicked(self):
        self.listModel.setStringList([])
        
    def onRemoveButtonClicked(self):
        if self.listView.currentIndex().isValid():
            row = self.listView.currentIndex().row()
            self.listModel.removeRows(row,  1,  QtCore.QModelIndex())
        
    def onOkButtonClicked(self):
        self.done(QtGui.QDialog.Accepted)
        
    def createSpinBox(self,  minimum,  maximum):
        edit = QtGui.QDoubleSpinBox()
        edit.setRange(minimum,  maximum)
        edit.setDecimals(3)
        return edit
    
    def dataList(self):
        return self.listModel.stringList()
